/* Qilin - a Java Pointer Analysis Framework
 * Copyright (C) 2021-2030 Qilin developers
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3.0 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * <https://www.gnu.org/licenses/lgpl-3.0.en.html>.
 */

package qilin.stat;

import qilin.CoreConfig;
import qilin.core.PTA;

/**
 * Gather stats on the performance and precision of a PTA run.
 *
 * <p>Each new run of the PTA will over-write stats
 *
 * <p>- Wall time (sec) - Memory (max, current) before and after - Reachable methods (context and
 * no-context) - Total reachable casts - Reachable casts that may fail - Call graph edges - Context
 * sensitive call graph edges - Total reachable virtual call sites - Polymorphic virtual call sites
 * (sites with &gt;1 target methods) - Number of pointers (local and global) - Total points to sets
 * size (local and global) context insensitive (convert to alloc site)
 */
public class PTAEvaluator implements IEvaluator {
  protected final RuntimeStat runtimeStat;
  protected final Exporter exporter;
  protected final PTA pta;

  public PTAEvaluator(PTA pta) {
    this.pta = pta;
    runtimeStat = new RuntimeStat();
    exporter = new Exporter(pta);
  }

  /** Note the start of a qilin.pta run. */
  @Override
  public void begin() {
    Runtime runtime = Runtime.getRuntime(); // Getting the runtime reference
    // from system
    exporter.addLine(" ====== Memory Usage ======");
    exporter.collectMetric(
        "Used Memory Before:",
        (runtime.totalMemory() - runtime.freeMemory()) / GB + " GB"); // Print
    // used memory
    exporter.collectMetric(
        "Free Memory Before:", runtime.freeMemory() / GB + " GB"); // Print free memory
    exporter.collectMetric(
        "Total Memory Before:", runtime.totalMemory() / GB + " GB"); // Print total available memory
    exporter.collectMetric(
        "Max Memory Before:", runtime.maxMemory() / GB + " GB"); // Print Maximum available memory
    exporter.collectMetric("Analysis: ", CoreConfig.v().getPtaConfig().ptaName);
    runtimeStat.begin();
  }

  /** Note the end of a qilin.pta run. */
  @Override
  public void end() {
    // done with processing
    runtimeStat.end();
    /** all method reachable from the harness main */
    PAGStat pagStat = new PAGStat(pta);
    BenchmarkStat benchmarkStat = new BenchmarkStat(pta);
    CallGraphStat callGraphStat = new CallGraphStat(pta);
    TypeClientStat typeClientStat = new TypeClientStat(pta);
    PointsToStat ptsStat = new PointsToStat(pta);
    AliasStat aliasStat = new AliasStat(pta);
    YummyStat yummyStat = new YummyStat(pta);
    runtimeStat.export(exporter);
    // memory stats
    Runtime runtime = Runtime.getRuntime(); // Getting the runtime reference
    // from system
    exporter.collectMetric(
        "Used Memory After:", (runtime.totalMemory() - runtime.freeMemory()) / GB + " GB"); // Print
    // used memory
    exporter.collectMetric(
        "Free Memory After:", runtime.freeMemory() / GB + " GB"); // Print free memory
    exporter.collectMetric(
        "Total Memory After:", runtime.totalMemory() / GB + " GB"); // Print total available memory
    exporter.collectMetric(
        "Max Memory After:", runtime.maxMemory() / GB + " GB"); // Print Maximum available memory
    exporter.addLine(" ====== Yummy ======");
    yummyStat.export(exporter);
    exporter.addLine(" ====== Call Graph ======");
    callGraphStat.export(exporter);
    exporter.addLine(" ====== Statements ======");
    typeClientStat.export(exporter);
    exporter.addLine(" ====== Nodes ======");
    ptsStat.export(exporter);
    exporter.addLine(" ====== Assignments ======");
    pagStat.export(exporter);
    exporter.addLine(" ====== Aliases ======");
    aliasStat.export(exporter);
    exporter.addLine(" ====== Classes ======");
    benchmarkStat.export(exporter);
  }

  @Override
  public String toString() {
    return exporter.report();
  }
}
